package com.manager.config

import com.base.model.admin_api.Model_AdminAPI_Shiro
import com.google.gson.Gson
import com.google.gson.internal.LinkedTreeMap
import com.manager.rpc.RPC_AdminAPI
import com.yfree.model.YBaseModel
import com.yfree.model.YModel
import org.apache.shiro.authc.AuthenticationInfo
import org.apache.shiro.authc.AuthenticationToken
import org.apache.shiro.authc.SimpleAuthenticationInfo
import org.apache.shiro.authz.AuthorizationInfo
import org.apache.shiro.authz.SimpleAuthorizationInfo
import org.apache.shiro.mgt.SecurityManager
import org.apache.shiro.realm.AuthorizingRealm
import org.apache.shiro.spring.web.ShiroFilterFactoryBean
import org.apache.shiro.subject.PrincipalCollection
import org.apache.shiro.web.mgt.DefaultWebSecurityManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component

@Configuration
class ShiroConfig(
    var realm: MyRealm
) {
    @Bean
    fun shiroFilter(securityManager: SecurityManager): ShiroFilterFactoryBean {
        val bean = ShiroFilterFactoryBean()
        //anon:不需要登录,authcBasic:需要登录，弹框,authc:需要登录，表单
        bean.filterChainDefinitionMap = mapOf(
            "/shiro_anon" to "anon",
            "/shiro_authc" to "authc",
            "/shiro_authcBasic" to "authcBasic",
            "/shiro_yfree1/*" to "roles[YFree1]",
            "/shiro_yfree2/*" to "roles[YFree2]"
        )
        bean.loginUrl = "/${IFinal.Page.ShiroLogin.rawValue}"
        bean.unauthorizedUrl = "/${IFinal.Page.ShiroUnauthorized.rawValue}"
        bean.securityManager = securityManager
        return bean
    }

    @Bean
    fun securityManager(): SecurityManager {
        val manager = DefaultWebSecurityManager()
        manager.setRealm(realm)
        return manager
    }
}

@Component
class MyRealm(
    val rpc_AdminAPI: RPC_AdminAPI
) : AuthorizingRealm() {
    var gson = Gson()

    //账号密码验证
    override fun doGetAuthenticationInfo(token: AuthenticationToken?): AuthenticationInfo? {
        val principal = token?.principal?.toString()
        val credentials = token?.credentials?.toString()
        if (principal.isNullOrEmpty()) return null
        if (credentials.isNullOrEmpty()) return null
        val result = fromRPC(
            rpc_AdminAPI.`interface`(
                IJkid.用户.登录_shiro.rawValue, mapOf(
                    "username" to principal
                )
            ), Model_AdminAPI_Shiro::class.java
        ) ?: return null
        val model = result.root.result.firstOrNull() ?: return null
        return SimpleAuthenticationInfo(principal, model.password, model.realname)
    }

    override fun doGetAuthorizationInfo(principals: PrincipalCollection?): AuthorizationInfo? {
        val principal = principals?.primaryPrincipal.toString()
        val result = fromRPC(
            rpc_AdminAPI.`interface`(
                IJkid.用户.登录_shiro.rawValue, mapOf(
                    "username" to principal
                )
            ), Model_AdminAPI_Shiro::class.java
        ) ?: return null
        val model = result.root.result.firstOrNull() ?: return null
        return SimpleAuthorizationInfo(model.roles.toSet())
    }

    //权限验证
    fun <T : YModel> fromRPC(json: String?, clazz: Class<T>, errorMessage: String? = null, successCode: HttpStatus = HttpStatus.OK): YBaseModel<T>? {
        val yModel = gson.fromJson<YBaseModel<T>>(json, YBaseModel::class.java)
        val ts = arrayListOf<T>()
        val map = gson.fromJson(json, Map::class.java)
        val result = (map["root"] as Map<String, Any>)["result"] as List<LinkedTreeMap<String, Any>>
        result.forEach {
            ts.add(gson.fromJson(gson.toJson(it), clazz))
        }
        yModel.root.result = ts
        if (yModel.root.code != successCode.value().toString()) return null
        return yModel
    }
}
